package gdma.hqdes.webapp.controller;

import gdma.hqdes.article.bean.RenderContext;
import gdma.hqdes.article.renderer.TemplateRenderer;
import gdma.hqdes.bean.Article;
import gdma.hqdes.bean.ArticleTemplate;
import gdma.hqdes.service.ArticleService;
import gdma.hqdes.service.ProjectService;
import gdma.hqdes.service.UnitService;
import io.swagger.annotations.ApiParam;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import sindconsole.auth.bean.User;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;

import static gdma.hqdes.Constants.ROLE_STATISTICIAN;

/**
 * @Author wangyue
 * @Version 3.0
 * @Date 2024-08-30
 */
@RestController
@RequestMapping("/api/articles")
@RequiresRoles(ROLE_STATISTICIAN)
public class ArticleController {

    public static final File APP_PATH = new File(".");

    public static final String ARTICLE_ROOT = "/files/article";

    @Autowired
    ProjectService projectService;

    @Autowired
    UnitService unitService;

    @Autowired
    ArticleService articleService;

    @Autowired
    TemplateRenderer templateRenderer;

    @GetMapping("")
    public Object listArticles(@RequestParam(value = "templateId", required = false) Integer templateId,
                               @RequestParam(value = "projectId", required = false) Long projectId,
                               @RequestParam(value = "unitId", required = false) Long unitId,
                               @RequestParam(value = "keyword", required = false) String keyword,
                               @ApiParam("页码，0开始") @RequestParam(value = "page", defaultValue = "0") int page,
                               @ApiParam("页长，默认20") @RequestParam(value = "pageSize", required = false) Integer pageSize) {
        int[] pagination = pageSize != null ? new int[] {page, pageSize} : new int[] {page};
        return articleService.listArticles(templateId, projectId, unitId, keyword, pagination);
    }

    @PostMapping("/preview")
    public void previewArticle(@RequestBody Article article,
                               @ApiIgnore HttpServletResponse response) {
        article = checkArticle(article);
        response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
        try(InputStream in = generateArticleFile(article);
            OutputStream out = response.getOutputStream()) {
            IOUtils.copy(in, out);
            out.flush();
        } catch(IOException e) {
            throw new RuntimeException(e);
        }
    }

    private Article checkArticle(Article article) {
        if(article.getProject() == null && article.getProjectId() != null)
            article.setProject(projectService.getProject(article.getProjectId()));
        if(article.getUnit() == null && article.getUnitId() != null)
            article.setUnit(unitService.getUnit(article.getUnitId()));
        if(article.getProject() != null && article.getProjectId() == null)
            article.setProjectId(article.getProject().getId());
        if(article.getUnit() != null && article.getUnitId() == null)
            article.setUnitId(article.getUnit().getId());
        return article;
    }

    private InputStream generateArticleFile(Article article) {
        ArticleTemplate template = articleService.getTemplate(article.getTemplateId());
        RenderContext renderContext = new RenderContext();
        renderContext.setProject(article.getProject());
        renderContext.setUnit(article.getUnit());
        return templateRenderer.render(new File(APP_PATH, template.getFilePath()), renderContext);
    }

    @PostMapping("")
    public Object createArticle(@RequestBody Article article,
                                @ApiIgnore User subjectUser) {
        article = checkArticle(article);
        article.setId(null);
        article.setDownloadPath("");
        article = articleService.saveArticle(article);

        String filePath = ARTICLE_ROOT + "/" + article.getProject().getYear() + "/" + article.getUnitId() + "/" + article.getId() + ".docx";
        File articleFile = new File(APP_PATH, filePath);
        articleFile.getParentFile().mkdirs();
        try(InputStream in = generateArticleFile(article);
            OutputStream out = new FileOutputStream(articleFile)) {
            IOUtils.copy(in, out);
        } catch(IOException e) {
            throw new RuntimeException(e);
        }

        article.setDownloadPath(filePath);
        article.setCreatorId(subjectUser.getId());
        article.setCreatedTime(new Date());
        return articleService.saveArticle(article);
    }

    @PostMapping("/{id}")
    public Object updateArticle(@PathVariable("id") Long id,
                                @RequestBody Article article,
                                @ApiIgnore User subjectUser) throws IOException {
        article = checkArticle(article);
        article.setId(id);

        Article article0 = articleService.getArticle(id);
        File articleFile0 = new File(APP_PATH, article0.getDownloadPath());
        File articleFile = new File(APP_PATH, article.getDownloadPath());
        boolean isRevised = !articleFile.equals(articleFile0) || !FileUtils.contentEquals(articleFile, articleFile0);

        if(isRevised) {
            String filePath = ARTICLE_ROOT + "/" + article.getProject().getYear() + "/" + article.getUnitId() + "/" + FilenameUtils.getName(articleFile.getName());
            File articleFile1 = new File(APP_PATH, filePath);
            articleFile1.delete();
            articleFile.renameTo(articleFile1);
            article.setDownloadPath(filePath);
            article.setReviserId(subjectUser.getId());
            article.setRevisedTime(new Date());
        } else {
            String filePath = ARTICLE_ROOT + "/" + article.getProject().getYear() + "/" + article.getUnitId() + "/" + article.getId() + ".docx";
            articleFile.delete();
            articleFile = new File(APP_PATH, filePath);
            article.setDownloadPath(filePath);
            article.setReviserId(null);
            article.setRevisedTime(null);
            articleFile.getParentFile().mkdirs();
            try(InputStream in = generateArticleFile(article);
                OutputStream out = new FileOutputStream(articleFile)) {
                IOUtils.copy(in, out);
            } catch(IOException e) {
                throw new RuntimeException(e);
            }
            article.setUpdatedTime(new Date());
        }

        return articleService.saveArticle(article);
    }

    @PostMapping("/{id}/delete")
    public Object deleteArticle(@PathVariable("id") Long id) throws IOException {
        Article article = articleService.getArticle(id);
        File articleFile = new File(article.getDownloadPath());
        articleFile.delete();
        return articleService.deleteArticle(id);
    }

}
